package com.opencee.cloud.uaa.handler;

import com.opencee.cloud.uaa.provider.service.AppClientDetailsService;
import com.opencee.cloud.uaa.token.CaptchaAuthenticationToken;
import com.opencee.cloud.uaa.token.SmsCodeAuthenticationToken;
import com.opencee.common.model.ApiResult;
import com.opencee.common.utils.SpringContextHolder;
import com.opencee.common.utils.WebUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.UnapprovedClientAuthenticationException;
import org.springframework.security.oauth2.provider.*;
import org.springframework.security.oauth2.provider.endpoint.AuthorizationEndpoint;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.web.bind.support.SimpleSessionStatus;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.view.RedirectView;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * 认证成功处理类,
 * SavedRequestAwareAuthenticationSuccessHandler 为默认处理类.
 * /oauth/authorize 跳转是基于session完成的. 所以要保证session会话一直,要保证必须在同域名下才可以.否是跳转将失效.
 * 可查看 SavedRequestAwareAuthenticationSuccessHandler.onAuthenticationSuccess();
 *
 * @author yadu
 */
@Slf4j
public class CustomAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {

    private ClientDetailsService clientDetailsService;

    private AuthorizationServerTokenServices authorizationServerTokenServices;

    private PasswordEncoder passwordEncoder;

    private AuthorizationEndpoint authorizationEndpoint;


    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
                                        Authentication authentication) throws IOException, ServletException {

        if (clientDetailsService == null) {
            clientDetailsService = SpringContextHolder.getBean(AppClientDetailsService.class);
        }
        if (authorizationServerTokenServices == null) {
            authorizationServerTokenServices = SpringContextHolder.getBean(AuthorizationServerTokenServices.class);
        }
        if (passwordEncoder == null) {
            passwordEncoder = SpringContextHolder.getBean(PasswordEncoder.class);
        }
        if (authorizationEndpoint == null) {
            authorizationEndpoint = SpringContextHolder.getBean(AuthorizationEndpoint.class);
        }

        // 验证码登录异步登录, 源至 org.springframework.security.oauth2.provider.endpoint.AuthorizationEndpoint
        if (WebUtil.acceptHasJson(request) && authentication instanceof CaptchaAuthenticationToken) {
            Map<String, Object> model = new HashMap<>();
            // 获取跳转访问路径
            ModelAndView modelAndView = authorizationEndpoint.authorize(model, WebUtil.getParameterMap(request), new SimpleSessionStatus(), authentication);
            View view = modelAndView.getView();
            if (view instanceof RedirectView) {
                // 响应数据
                String url = ((RedirectView) view).getUrl();
                Map<String, String> data = new HashMap<>(2);
                data.put("url", url);
                WebUtil.writeJson(response, ApiResult.ok().data(data));
                return;
            }
        }
        // 手机验证码登录直接返回token
        if (WebUtil.acceptHasJson(request) && authentication instanceof SmsCodeAuthenticationToken) {
            String clientId = request.getParameter("client_id");
            String clientSecret = request.getParameter("client_secret");

            if (clientId == null) {
                throw new BadCredentialsException("No client_id credentials presented");
            }

            if (clientSecret == null) {
                clientSecret = "";
            }
            ClientDetails clientDetails = clientDetailsService.loadClientByClientId(clientId);
            if (null == clientDetails) {
                throw new UnapprovedClientAuthenticationException("clientId不存在" + clientId);
            } else if (passwordEncoder.matches(clientSecret, clientDetails.getClientSecret())) {
                throw new UnapprovedClientAuthenticationException("clientSecret不匹配" + clientId);
            }
            Map<String, String> parameterMap = WebUtil.getParameterMap(request);
            TokenRequest tokenRequest = new TokenRequest(parameterMap, clientId, clientDetails.getScope(), "sms");
            OAuth2Request oAuth2Request = tokenRequest.createOAuth2Request(clientDetails);
            OAuth2Authentication oAuth2Authentication = new OAuth2Authentication(oAuth2Request, authentication);
            OAuth2AccessToken token = authorizationServerTokenServices.createAccessToken(oAuth2Authentication);
            WebUtil.writeJson(response, token);
            return;
        }
        super.onAuthenticationSuccess(request, response, authentication);
    }

}
